package com.gitee.l0km.xthrift.base.metadata;

import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Pattern;

import javax.annotation.Nullable;

import com.google.common.base.Optional;
import com.google.common.base.Predicate;

public class PatternFilter implements Predicate<String> {
	public final String pattern;
	private final AtomicReference<Pattern> patternRef = new AtomicReference<>(null);
	private final AtomicReference<Optional<Pattern>> starPatternRef = new AtomicReference<>(null);
	private final AtomicReference<Optional<Pattern>> questionPatternRef = new AtomicReference<>(null);
	private boolean startsWithAsTrue;
	
	public PatternFilter(String pattern) {
		this(pattern,true);
	}
	
	public PatternFilter(String pattern,boolean startsWithAsTrue) {
		super();
		this.pattern = pattern;
		this.startsWithAsTrue = startsWithAsTrue;
	}
	
	private Pattern pattern() {
		if (patternRef.get() == null) {
			synchronized (patternRef) {
				if (patternRef.get() == null) {
					patternRef.set(Pattern.compile(pattern));
				}
			}
		}
		return patternRef.get();
	}
	
	private Optional<Pattern> starPattern() {
		if (starPatternRef.get() == null) {
			synchronized (starPatternRef) {
				if (starPatternRef.get() == null) {
					starPatternRef.set(pattern.indexOf('*') >= 0 ? 
						Optional.of(Pattern.compile(pattern.replaceAll("\\*+", "\\\\S*"))) : 
						Optional.<Pattern>absent());
				}
			}
		}
		return starPatternRef.get();
	}
	
	private Optional<Pattern> questionPattern() {
		if (questionPatternRef.get() == null) {
			synchronized (questionPatternRef) {
				if (questionPatternRef.get() == null) {
					questionPatternRef.set(pattern.indexOf('?') >= 0 ? 
						Optional.of(Pattern.compile(pattern.replace("?", "\\S"))) : 
						Optional.<Pattern>absent());
				}
			}
		}
		return questionPatternRef.get();
	}
	
	@Override
	public boolean apply(@Nullable String input) {
		if(null == input) {
			return false;
		}else if(startsWithAsTrue && input.startsWith(pattern)){
			return true;
		}else if(pattern().matcher(input).matches()){
			return true;
		}else if(starPattern().isPresent() && starPattern().get().matcher(input).matches()){
			return true;
		}else if(questionPattern().isPresent() && questionPattern().get().matcher(input).matches()){
			return true;
		}
		return false;
	}
	
	public static boolean filter(String pattern,String input){
		return new PatternFilter(pattern).apply(input);
	}
	
	public static boolean filter(String pattern,String input,boolean startsWithAsTrue){
		return new PatternFilter(pattern,startsWithAsTrue).apply(input);
	}
}